panic 狀況其實也非不能補救,Go語言提供了 recover() 函式,可以在某個 Goroutine 發生 panic 後取回控制權。
recover() 函式定義如下 :
func recover() interface{}
recover() 函數沒有參數,傳回值則是一個空值,這意味著回傳資料可以是任意型別。實際上 recover 傳回的值是你一開始傳給 panic 的值
**recover() 只是在使用 defer 延遲執行的函式中才有作用。**如前幾篇說到,延遲的函式會在外層函式結束前一刻執行。如果你在延遲執行函式中呼叫recover(),就可以恢復正常執行和停止panic。
相反的,但若recover函式是在延遲函式外的地方呼叫,就無法阻止panic
接下來看一個例子,包含 panic()、recover() 和 defer 時的過程 :
package main
import (
"errors"
"fmt"
)
func main() {
a()
fmt.Println("這一行現在會印出")
}
func a() {
b("good-bye")
fmt.Println("返回上一層a()")
}
func b(msg string) {
defer func() {
if r:= recover(); r != nil {
fmt.Println("b() 發生錯誤: ", r) //印出error
}
}()
if msg == "good-bye" {
panic(errors.New("阿北 出事了阿北")) // 引發panic
}
}
執行結果 :
不管 b() 有沒有發生 panic 都會呼叫延遲執行的匿名函式,而這個匿名函式會去呼叫recover(),如果recover回傳回來的error值是nil,代表b()沒有發生panic,反之,就是有panic,則印出 error 值。
因為recover阻止b()內發生panic,所以panic就不會往上傳到a()或是main(),最終讓程式掛掉。
在錯誤處理這個主題中,知道了如何建立並回傳自訂error,必要時如何用panic()讓程式掛掉,最後則是如何從panic 復原、並在復原時根據傳panic()函式的error值來顯示錯誤訊息。
此外,在使用其他套件時,他們所引發的panic也不建議使用recover()去救,因為難確認救回來的套件式處於何種狀態,繼續使用上可能會有其他問題。
比起其他語言錯誤處理,Go語言處理語法相對單純,簡單的整理本主題:
package main
import (
"errors"
"fmt"
)
var (
ErrFileNotFound = errors.New("檔案找不到")
ErrNetworkConnection = errors.New("網路連線失敗")
)
func main() {
err := openFile("example.txt")
if err != nil {
fmt.Println("發生錯誤:", err)
}
err = establishNetworkConnection()
if err != nil {
fmt.Println("發生錯誤:", err)
}
}
func openFile(filename string) error {
// 模擬檔案未找到的狀況
return ErrFileNotFound
}
func establishNetworkConnection() error {
// 模擬網路連線失敗的情況
return ErrNetworkConnection
}
以上就是Go錯誤處理的主題整理,下一篇開始會進入到介面的部分。